﻿using System.Collections.Generic;
using Commands.Mafia.Models;

namespace Commands.Mafia
{
    using System;
    using System.Linq;
    using System.Threading;
    using Commands.Mafia.Enums;
    using SkypeBot.Core;
    using SkypeBotCore;

    public class MafiaCore
    {
        private const string ChoosePlayerMessage = "Выберите игрока: \r\n";
        private const string CheckOnMafiaMessage = "Выберите игрока для проверки. (!check_{PlayerName})";
        private const string MafiasVictimChoosenMessage = "Выберите игрока для убийства. (!kill_{PlayerName})";
        private const string PlayerHaveBeenRegisterMessage = "Учасник, {0}, зарегистрирован.";
        private const string RoleMessage = "Твоя роль в текущей игре {0}";
        private const string AlreadyRegisterMessage = "Вы уже зарегистрированы!";
        private const string IsMafiaMessage = "Учасник, {0}, {1}!";

        private static IList<PlayerModel> _players;
        private static Array _indexesArray;
        private static bool _isDetectiveCheckedPlayer;
        private static bool _isGameFinished;
        private static int _attemptTillInterrupt;
        private static bool _isMafiasVictimChoosen;
        private static RandomGenerator _randomGenerator;

        static MafiaCore()
        {
            _players = new List<PlayerModel>();
        }

        public static string RegisterPlayer(string playerName)
        {
            if (_players.All(p => p.Name != playerName))
            {
                _players.Add(new PlayerModel(playerName));
                return string.Format(PlayerHaveBeenRegisterMessage, playerName);
            }

            return AlreadyRegisterMessage;
        }

        public static void StartGame()
        {
            AssignRolesToPlayers();
            SendEveryoneRoleNotification();
            FillAllPlayersLists();
            while (!_isGameFinished)
            {
                while (_isDetectiveCheckedPlayer || _attemptTillInterrupt == 5)
                {
                    SendMafiaDetectionMessageToDetective();
                    Thread.Sleep(TimeSpan.FromMinutes(1));
                    _attemptTillInterrupt++;
                }

                _attemptTillInterrupt = 0;

                while (_isMafiasVictimChoosen || _attemptTillInterrupt == 5)
                {
                    SendPlayersListToMafia();
                    Thread.Sleep(TimeSpan.FromMinutes(1));
                    _attemptTillInterrupt++;
                }
            }
        }

        public static void CheckIfMafiaForDetective(string senderName, string checkedPlayer)
        { 
            var playerDetective = _players.FirstOrDefault(p => p.Role == Roles.Detective);
            if (playerDetective != null && senderName == playerDetective.Name)
            {
                var isMafia = _players.Any(p => p.Name == checkedPlayer && p.Role == Roles.Mafia);
                var answer = string.Format(IsMafiaMessage, checkedPlayer, isMafia ? "Мафия" : "не Мафия");
                Core.Instance.SendMessage(playerDetective.Name, answer, false);
                _isDetectiveCheckedPlayer = true;
            }
        }

        public static void MafiasOption(string senderName, string victimName)
        {
            if (_players.Any(p => p.Name == senderName && p.Role == Roles.Mafia))
            {
                // ToDo: Need to use something like mafia list
            }
        }

        private static void AssignRolesToPlayers()
        {
            FillIndexArray();
            if (_players.Count > 3)
            {
                _randomGenerator = new RandomGenerator();
                var detectiveIndex = _randomGenerator.Next(_indexesArray.Length);
                _players[(int)_indexesArray.GetValue(detectiveIndex)].Role = Roles.Detective;
                RemoveValueFromArray(detectiveIndex);
                var koef = 0.3f * (_players.Count - 1);
                var mafiasCount = (int)(koef < 1.0 ? 1 : Math.Round(koef));
                var citizenCount = _players.Count - mafiasCount - 1;
                for (int i = 0; i < mafiasCount; i++)
                {
                    var mafiasIndex = _randomGenerator.Next(_indexesArray.Length);
                    _players[(int)_indexesArray.GetValue(mafiasIndex)].Role = Roles.Mafia;
                    RemoveValueFromArray(mafiasIndex);
                }
                for (int i = 0; i < citizenCount; i++)
                {
                    var citizenIndex = _randomGenerator.Next(_indexesArray.Length);
                    _players[(int)_indexesArray.GetValue(citizenIndex)].Role = Roles.Citizen;
                    RemoveValueFromArray(citizenIndex);
                }
            }
            else
            {
                // ToDo: Stop game
            }
        }

        private static void FillIndexArray()
        {
            var indexList = new List<int>();
            for (int i = 0; i < _players.Count; i++)
            {
                indexList.Add(i);
            }
            _indexesArray = indexList.ToArray();
        }

        private static void RemoveValueFromArray(int value)
        {
            var list = _indexesArray.OfType<int>().ToList();
            list.Remove(value);
            _indexesArray = list.ToArray();
        }

        private static void SendEveryoneRoleNotification()
        {
            foreach (var player in _players)
            {
                var answer = string.Format(RoleMessage, player.Role);
                Core.Instance.SendMessage(player.Name, answer, false);
            }
        }

        private static void SendMafiaDetectionMessageToDetective()
        {
            var playerDetective = _players.FirstOrDefault(p => p.Role == Roles.Detective);
            if (playerDetective != null)
            {
                Core.Instance.SendMessage(playerDetective.Name, CheckOnMafiaMessage, false);
            }
        }

        private static void SendPlayersListToMafia()
        {
            foreach (var player in _players.Where(p => p.Role == Roles.Mafia))
            {
                Core.Instance.SendMessage(player.Name, MafiasVictimChoosenMessage, false);
            }
        }

        private static void FillAllPlayersLists()
        {
            foreach (var player in _players)
            {
                FillPlayerList(player);
            }
        }

        private static void FillPlayerList(PlayerModel currentPlayer)
        {
            currentPlayer.PlayerList = new Dictionary<int, string>();
            for(int i = 0; i < _players.Count; i++)
            {
                if (_players[i] != currentPlayer)
                {
                    currentPlayer.PlayerList.Add(i, _players[i].Name);
                }
            }
        }

        private void SendPlayersOptions(PlayerModel currentPlayer)
        {
            Core.Instance.SendMessage(currentPlayer.Name, CreateOptionList(currentPlayer), false);
        }

        private static string CreateOptionList(PlayerModel currentPlayer)
        {
            string message = ChoosePlayerMessage;
            foreach (var item in currentPlayer.PlayerList)
            {
                message += string.Format("{0} - {1}{2}", item.Key, item.Value, Environment.NewLine);
            }
            return message;
        }
    }
}
